home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / cvs-1_3.lha / cvs-1.3 / src / rtag.c < prev    next >
C/C++ Source or Header  |  1992-04-09  |  10KB  |  404 lines

  1. /*
  2.  * Copyright (c) 1992, Brian Berliner and Jeff Polk
  3.  * Copyright (c) 1989-1992, Brian Berliner
  4.  * 
  5.  * You may distribute under the terms of the GNU General Public License as
  6.  * specified in the README file that comes with the CVS 1.3 kit.
  7.  * 
  8.  * Rtag
  9.  * 
  10.  * Add or delete a symbolic name to an RCS file, or a collection of RCS files.
  11.  * Uses the modules database, if necessary.
  12.  */
  13.  
  14. #include "cvs.h"
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "@(#)rtag.c 1.57 92/04/10";
  18. #endif
  19.  
  20. #if __STDC__
  21. static Dtype rtag_dirproc (char *dir, char *repos, char *update_dir);
  22. static int rtag_fileproc (char *file, char *update_dir,
  23.               char *repository, List * entries,
  24.               List * srcfiles);
  25. static int rtag_proc (int *pargc, char *argv[], char *xwhere,
  26.               char *mwhere, char *mfile, int shorten,
  27.               int local_specified, char *mname, char *msg);
  28. static int rtag_delete (RCSNode *rcsfile);
  29. #else
  30. static int rtag_proc ();
  31. static int rtag_fileproc ();
  32. static Dtype rtag_dirproc ();
  33. static int rtag_delete ();
  34. #endif                /* __STDC__ */
  35.  
  36. static char *symtag;
  37. static char *numtag;
  38. static int delete;            /* adding a tag by default */
  39. static int attic_too;            /* remove tag from Attic files */
  40. static int branch_mode;            /* make an automagic "branch" tag */
  41. static char *date;
  42. static int local;            /* recursive by default */
  43. static int force_tag_match = 1;        /* force by default */
  44.  
  45. static char *rtag_usage[] =
  46. {
  47.     "Usage: %s %s [-QaflRnq] [-b] [-d] [-r tag|-D date] tag modules...\n",
  48.     "\t-Q\tReally quiet.\n",
  49.     "\t-a\tClear tag from removed files that would not otherwise be tagged.\n",
  50.     "\t-f\tForce a head revision match if tag/date not found.\n",
  51.     "\t-l\tLocal directory only, not recursive\n",
  52.     "\t-R\tProcess directories recursively.\n",
  53.     "\t-n\tNo execution of 'tag program'\n",
  54.     "\t-q\tSomewhat quiet.\n",
  55.     "\t-d\tDelete the given Tag.\n",
  56.     "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n",
  57.     "\t-[rD]\tExisting tag or Date.\n",
  58.     NULL
  59. };
  60.  
  61. int
  62. rtag (argc, argv)
  63.     int argc;
  64.     char *argv[];
  65. {
  66.     register int i;
  67.     int c;
  68.     DBM *db;
  69.     int run_module_prog = 1;
  70.     int err = 0;
  71.  
  72.     if (argc == -1)
  73.     usage (rtag_usage);
  74.  
  75.     optind = 1;
  76.     while ((c = gnu_getopt (argc, argv, "anfQqlRdbr:D:")) != -1)
  77.     {
  78.     switch (c)
  79.     {
  80.         case 'a':
  81.         attic_too = 1;
  82.         break;
  83.         case 'n':
  84.         run_module_prog = 0;
  85.         break;
  86.         case 'Q':
  87.         really_quiet = 1;
  88.         /* FALL THROUGH */
  89.         case 'q':
  90.         quiet = 1;
  91.         break;
  92.         case 'l':
  93.         local = 1;
  94.         break;
  95.         case 'R':
  96.         local = 0;
  97.         break;
  98.         case 'd':
  99.         delete = 1;
  100.         break;
  101.         case 'f':
  102.         force_tag_match = 0;
  103.         break;
  104.         case 'b':
  105.         branch_mode = 1;
  106.         break;
  107.         case 'r':
  108.         numtag = optarg;
  109.         break;
  110.         case 'D':
  111.         if (date)
  112.             free (date);
  113.         date = Make_Date (optarg);
  114.         break;
  115.         case '?':
  116.         default:
  117.         usage (rtag_usage);
  118.         break;
  119.     }
  120.     }
  121.     argc -= optind;
  122.     argv += optind;
  123.     if (argc < 2)
  124.     usage (rtag_usage);
  125.     symtag = argv[0];
  126.     argc--;
  127.     argv++;
  128.  
  129.     if (date && numtag)
  130.     error (1, 0, "-r and -D options are mutually exclusive");
  131.     if (delete && branch_mode)
  132.     error (0, 0, "warning: -b ignored with -d options");
  133.     RCS_check_tag (symtag);
  134.  
  135.     db = open_module ();
  136.     for (i = 0; i < argc; i++)
  137.     {
  138.     /* XXX last arg should be repository, but doesn't make sense here */
  139.     history_write ('T', (delete ? "D" : (numtag ? numtag : 
  140.                (date ? date : "A"))), symtag, argv[i], "");
  141.     err += do_module (db, argv[i], TAG, delete ? "Untagging" : "Tagging",
  142.               rtag_proc, (char *) NULL, 0, 0, run_module_prog,
  143.               symtag);
  144.     }
  145.     close_module (db);
  146.     return (err);
  147. }
  148.  
  149. /*
  150.  * callback proc for doing the real work of tagging
  151.  */
  152. /* ARGSUSED */
  153. static int
  154. rtag_proc (pargc, argv, xwhere, mwhere, mfile, shorten, local_specified,
  155.        mname, msg)
  156.     int *pargc;
  157.     char *argv[];
  158.     char *xwhere;
  159.     char *mwhere;
  160.     char *mfile;
  161.     int shorten;
  162.     int local_specified;
  163.     char *mname;
  164.     char *msg;
  165. {
  166.     int err = 0;
  167.     int which;
  168.     char repository[PATH_MAX];
  169.     char where[PATH_MAX];
  170.  
  171.     (void) sprintf (repository, "%s/%s", CVSroot, argv[0]);
  172.     (void) strcpy (where, argv[0]);
  173.  
  174.     /* if mfile isn't null, we need to set up to do only part of the module */
  175.     if (mfile != NULL)
  176.     {
  177.     char *cp;
  178.     char path[PATH_MAX];
  179.  
  180.     /* if the portion of the module is a path, put the dir part on repos */
  181.     if ((cp = rindex (mfile, '/')) != NULL)
  182.     {
  183.         *cp = '\0';
  184.         (void) strcat (repository, "/");
  185.         (void) strcat (repository, mfile);
  186.         (void) strcat (where, "/");
  187.         (void) strcat (where, mfile);
  188.         mfile = cp + 1;
  189.     }
  190.  
  191.     /* take care of the rest */
  192.     (void) sprintf (path, "%s/%s", repository, mfile);
  193.     if (isdir (path))
  194.     {
  195.         /* directory means repository gets the dir tacked on */
  196.         (void) strcpy (repository, path);
  197.         (void) strcat (where, "/");
  198.         (void) strcat (where, mfile);
  199.     }
  200.     else
  201.     {
  202.         int i;
  203.  
  204.         /* a file means muck argv */
  205.         for (i = 1; i < *pargc; i++)
  206.         free (argv[i]);
  207.         argv[1] = xstrdup (mfile);
  208.         (*pargc) = 2;
  209.     }
  210.     }
  211.  
  212.     /* chdir to the starting directory */
  213.     if (chdir (repository) < 0)
  214.     {
  215.     error (0, errno, "cannot chdir to %s", repository);
  216.     return (1);
  217.     }
  218.  
  219.     if (delete || attic_too || (force_tag_match && numtag))
  220.     which = W_REPOS | W_ATTIC;
  221.     else
  222.     which = W_REPOS;
  223.  
  224.     /* start the recursion processor */
  225.     err = start_recursion (rtag_fileproc, (int (*) ()) NULL, rtag_dirproc,
  226.                (int (*) ()) NULL, *pargc - 1, argv + 1, local,
  227.                which, 0, 1, where, 1);
  228.  
  229.     return (err);
  230. }
  231.  
  232. /*
  233.  * Called to tag a particular file, as appropriate with the options that were
  234.  * set above.
  235.  */
  236. /* ARGSUSED */
  237. static int
  238. rtag_fileproc (file, update_dir, repository, entries, srcfiles)
  239.     char *file;
  240.     char *update_dir;
  241.     char *repository;
  242.     List *entries;
  243.     List *srcfiles;
  244. {
  245.     Node *p;
  246.     RCSNode *rcsfile;
  247.     char *version, *rev;
  248.     int retcode = 0;
  249.  
  250.     /* find the parsed RCS data */
  251.     p = findnode (srcfiles, file);
  252.     if (p == NULL)
  253.     return (1);
  254.     rcsfile = (RCSNode *) p->data;
  255.  
  256.     /*
  257.      * For tagging an RCS file which is a symbolic link, you'd best be
  258.      * running with RCS 5.6, since it knows how to handle symbolic links
  259.      * correctly without breaking your link!
  260.      */
  261.  
  262.     if (delete)
  263.     return (rtag_delete (rcsfile));
  264.  
  265.     /*
  266.      * If we get here, we are adding a tag.  But, if -a was specified, we
  267.      * need to check to see if a -r or -D option was specified.  If neither
  268.      * was specified and the file is in the Attic, remove the tag.
  269.      */
  270.     if (attic_too && (!numtag && !date))
  271.     {
  272.     if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC))
  273.         return (rtag_delete (rcsfile));
  274.     }
  275.  
  276.     version = RCS_getversion (rcsfile, numtag, date, force_tag_match);
  277.     if (version == NULL)
  278.     {
  279.     /* If -a specified, clean up any old tags */
  280.     if (attic_too)
  281.         (void) rtag_delete (rcsfile);
  282.  
  283.     if (!quiet && !force_tag_match)
  284.     {
  285.         error (0, 0, "cannot find tag `%s' in `%s'",
  286.            numtag ? numtag : "head", rcsfile->path);
  287.         return (1);
  288.     }
  289.     return (0);
  290.     }
  291.     if (numtag && isdigit (*numtag) && strcmp (numtag, version) != 0)
  292.     {
  293.  
  294.     /*
  295.      * We didn't find a match for the numeric tag that was specified, but
  296.      * that's OK.  just pass the numeric tag on to rcs, to be tagged as
  297.      * specified.  Could get here if one tried to tag "1.1.1" and there
  298.      * was a 1.1.1 branch with some head revision.  In this case, we want
  299.      * the tag to reference "1.1.1" and not the revision at the head of
  300.      * the branch.  Use a symbolic tag for that.
  301.      */
  302.     rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag;
  303.     run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, numtag);
  304.     }
  305.     else
  306.     {
  307.     char *oversion;
  308.  
  309.     /*
  310.      * As an enhancement for the case where a tag is being re-applied to
  311.      * a large body of a module, make one extra call to Version_Number to
  312.      * see if the tag is already set in the RCS file.  If so, check to
  313.      * see if it needs to be moved.  If not, do nothing.  This will
  314.      * likely save a lot of time when simply moving the tag to the
  315.      * "current" head revisions of a module -- which I have found to be a
  316.      * typical tagging operation.
  317.      */
  318.     oversion = RCS_getversion (rcsfile, symtag, (char *) 0, 1);
  319.     if (oversion != NULL)
  320.     {
  321.         if (strcmp (version, oversion) == 0)
  322.         {
  323.         free (version);
  324.         free (oversion);
  325.         return (0);
  326.         }
  327.         free (oversion);
  328.     }
  329.     rev = branch_mode ? RCS_magicrev (rcsfile, version) : version;
  330.     run_setup ("%s%s -q -N%s:%s", Rcsbin, RCS, symtag, rev);
  331.     }
  332.     run_arg (rcsfile->path);
  333.     if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0)
  334.     {
  335.     if (!quiet)
  336.         error (0, retcode == -1 ? errno : 0,
  337.            "failed to set tag `%s' to revision `%s' in `%s'",
  338.            symtag, rev, rcsfile->path);
  339.     free (version);
  340.     return (1);
  341.     }
  342.     free (version);
  343.     return (0);
  344. }
  345.  
  346. /*
  347.  * If -d is specified, "force_tag_match" is set, so that this call to
  348.  * Version_Number() will return a NULL version string if the symbolic
  349.  * tag does not exist in the RCS file.
  350.  * 
  351.  * If the -r flag was used, numtag is set, and we only delete the
  352.  * symtag from files that have numtag.
  353.  * 
  354.  * This is done here because it's MUCH faster than just blindly calling
  355.  * "rcs" to remove the tag... trust me.
  356.  */
  357. static int
  358. rtag_delete (rcsfile)
  359.     RCSNode *rcsfile;
  360. {
  361.     char *version;
  362.     int retcode;
  363.  
  364.     if (numtag)
  365.     {
  366.     version = RCS_getversion (rcsfile, numtag, (char *) 0, 1);
  367.     if (version == NULL)
  368.         return (0);
  369.     free (version);
  370.     }
  371.  
  372.     version = RCS_getversion (rcsfile, symtag, (char *) 0, 1);
  373.     if (version == NULL)
  374.     return (0);
  375.     free (version);
  376.  
  377.     run_setup ("%s%s -q -N%s", Rcsbin, RCS, symtag);
  378.     run_arg (rcsfile->path);
  379.     if ((retcode = run_exec (RUN_TTY, RUN_TTY, DEVNULL, RUN_NORMAL)) != 0)
  380.     {
  381.     if (!quiet)
  382.         error (0, retcode == -1 ? errno : 0,
  383.            "failed to remove tag `%s' from `%s'", symtag,
  384.            rcsfile->path);
  385.     return (1);
  386.     }
  387.     return (0);
  388. }
  389.  
  390. /*
  391.  * Print a warm fuzzy message
  392.  */
  393. /* ARGSUSED */
  394. static Dtype
  395. rtag_dirproc (dir, repos, update_dir)
  396.     char *dir;
  397.     char *repos;
  398.     char *update_dir;
  399. {
  400.     if (!quiet)
  401.     error (0, 0, "%s %s", delete ? "Untagging" : "Tagging", update_dir);
  402.     return (R_PROCESS);
  403. }
  404.